package com.alogic.markdown.xscript;

import com.alogic.xscript.AbstractLogiclet;
import com.alogic.xscript.ExecuteWatcher;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.doc.XsObject;
import com.alogic.xscript.plugins.Segment;
import com.anysoft.util.*;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.List;

/**
 * Markdown中的table
 *
 * @version 1.6.12.58 [20200113]
 */
public class MDTable extends Segment {
    protected String cid = "$md-table";
    /**
     * 上下文id
     */
    protected String pid = "$h-conf";

    public MDTable(String tag, Logiclet p) {
        super(tag, p);

        registerModule("m-table",MDTable.class);
        registerModule("m-column",MDColumn.class);
        registerModule("m-row",MDRow.class);
    }

    @Override
    public void configure(Properties p){
        super.configure(p);
        pid = PropertiesConstants.getString(p, "pid", pid,true);
        cid = PropertiesConstants.getString(p,"cid",cid,true);
    }

    @Override
    protected void onExecute(XsObject root, XsObject current, final LogicletContext ctx, final ExecuteWatcher watcher){
        StringBuffer content = ctx.getObject(pid);
        if (content == null){
            throw new BaseException("core.e1001","It must be in a h-conf context,check your script.");
        }

        try{
            Table table = new Table();
            ctx.setObject(cid,table);
            super.onExecute(root,current,ctx,watcher);

            //输出table
            content.append('\n');
            for (int i = 0 ; i < table.getColumnCnt() ; i ++){
                Column column = table.getColumn(i);
                content.append("| ").append(column.getTitle()).append(" ");
            }
            content.append("|");
            content.append('\n');
            for (int i = 0 ; i < table.getColumnCnt() ; i ++){
                content.append("| ");
                Column column = table.getColumn(i);
                switch (column.getAlign()){
                    case LEFT:
                        content.append(":---- ");
                        break;
                    case CENTER:
                        content.append(":----: ");
                        break;
                    case RIGHT:
                        content.append("----: ");
                        break;
                }
            }
            content.append("|");

            for (int i = 0 ; i < table.getRowCnt(); i ++){
                Row row = table.getRow(i);
                if (row != null) {
                    content.append("\n");
                    for (int j = 0; j < table.getColumnCnt(); j++) {
                        content.append("| ").append(row.getCell(j,"")).append(" ");
                    }
                    content.append("|");
                }
            }
        }finally{
            ctx.removeObject(cid);
        }
    }

    public static class MDColumn extends AbstractLogiclet{
        protected String pid = "$md-table";
        protected String $title = "";
        protected Column.Align align = Column.Align.LEFT;

        public MDColumn(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            pid = PropertiesConstants.getString(p, "pid", pid,true);
            $title = PropertiesConstants.getRaw(p,"title","");
            align = Column.Align.valueOf(PropertiesConstants.getString(p,"align", Column.Align.LEFT.name()));
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, final LogicletContext ctx, final ExecuteWatcher watcher){
            Table table = ctx.getObject(pid);
            if (table != null){
                String title = PropertiesConstants.transform(ctx, $title, "");
                table.addColumn(table.newColumn(title,align));
            }
        }
    }

    public static class MDRow extends AbstractLogiclet{
        protected String pid = "$md-table";
        protected List<String> rows = new ArrayList<String>();

        public MDRow(String tag, Logiclet p) {
            super(tag, p);
        }

        @Override
        public void configure(Properties p){
            super.configure(p);
            pid = PropertiesConstants.getString(p, "pid", pid,true);
        }

        @Override
        public void configure(Element e, Properties p) {
            Properties props = new XmlElementProperties(e,p);
            configure(props);

            NodeList nodeList = XmlTools.getNodeListByPath(e,"cell");
            for (int i = 0 ; i < nodeList.getLength() ; i ++){
                Node node = nodeList.item(i);
                if (Element.ELEMENT_NODE != node.getNodeType()){
                    continue;
                }
                Element cellElement = (Element)node;
                String value = cellElement.getAttribute("value");
                if (StringUtils.isNotEmpty(value)){
                    rows.add(value);
                }
            }
        }

        @Override
        protected void onExecute(XsObject root, XsObject current, final LogicletContext ctx, final ExecuteWatcher watcher){
            Table table = ctx.getObject(pid);
            if (table != null){
                Row row = table.newRow();
                for (String p:rows){
                    String value = PropertiesConstants.transform(ctx,p,"");
                    row.addCell(value);
                }
                table.addRow(row);
            }
        }
    }

    public static class Row {
        protected List<String> cells = null;
        protected int columnCnt;
        public Row(int columnCnt){
            this.columnCnt = columnCnt > 0?columnCnt:0;
            this.cells = new ArrayList<String>(columnCnt);
        }

        protected void addCell(String cell){
            if (cells.size() < columnCnt) {
                cells.add(cell);
            }
        }

        public String getCell(int index,String dft){
            return index < 0 || index >= cells.size() ? dft : cells.get(index);
        }
    }

    public static class Column {

        public enum Align{
            LEFT,
            CENTER,
            RIGHT
        };

        protected String title;
        protected Align align;

        public Column(String title,Align align){
            this.title = title;
            this.align = align;
        }

        public String getTitle(){
            return this.title;
        }
        public Align getAlign(){
            return this.align;
        }
    }

    /**
     * table对象
     */
    public static class Table {
        /**
         * 列
         */
        protected List<Column> columns = new ArrayList<Column>();

        /**
         * 行
         */
        protected List<Row> rows = new ArrayList<Row>();

        public Table(){

        }

        public Column newColumn(String title, Column.Align align){
            return new Column(title,align);
        }

        public void addColumn(Column column){
            columns.add(column);
        }

        public Row newRow(){
            return new Row(columns.size());
        }

        public void addRow(Row row){
            if (row != null) {
                rows.add(row);
            }
        }

        public int getRowCnt(){
            return rows.size();
        }

        public Row getRow(int index){
            return index < 0 || index >= rows.size() ? null : rows.get(index);
        }

        public int getColumnCnt(){
            return columns.size();
        }

        public Column getColumn(int index){
            return index < 0 || index >= columns.size() ? null : columns.get(index);
        }
    }
}
